package org.fireflow2.designer.eclipse.modelwrapper;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.fireflow.model.ModelElement;
import org.fireflow.model.resourcedef.ResourceDef;
import org.fireflow.model.servicedef.ServiceDef;
import org.fireflow.pdl.fpdl20.diagram.ActivityShape;
import org.fireflow.pdl.fpdl20.diagram.Diagram;
import org.fireflow.pdl.fpdl20.diagram.DiagramElement;
import org.fireflow.pdl.fpdl20.diagram.EndNodeShape;
import org.fireflow.pdl.fpdl20.diagram.RouterShape;
import org.fireflow.pdl.fpdl20.diagram.StartNodeShape;
import org.fireflow.pdl.fpdl20.diagram.TransitionShape;
import org.fireflow.pdl.fpdl20.diagram.WorkflowNodeShape;
import org.fireflow.pdl.fpdl20.diagram.impl.ActivityShapeImpl;
import org.fireflow.pdl.fpdl20.diagram.impl.DiagramImpl;
import org.fireflow.pdl.fpdl20.diagram.impl.EndNodeShapeImpl;
import org.fireflow.pdl.fpdl20.diagram.impl.RouterShapeImpl;
import org.fireflow.pdl.fpdl20.diagram.impl.StartNodeShapeImpl;
import org.fireflow.pdl.fpdl20.diagram.impl.TransitionShapeImpl;
import org.fireflow.pdl.fpdl20.process.Activity;
import org.fireflow.pdl.fpdl20.process.EndNode;
import org.fireflow.pdl.fpdl20.process.Router;
import org.fireflow.pdl.fpdl20.process.StartNode;
import org.fireflow.pdl.fpdl20.process.SubProcess;
import org.fireflow.pdl.fpdl20.process.Transition;
import org.fireflow.pdl.fpdl20.process.WorkflowProcess;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ResourceDefWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ServiceDefWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.ImportListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.ResourceListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.ServiceListWrapper;

public class WorkflowProcessWrapper extends ModelWrapper  implements PropertyChangeListener{	
	boolean dirty = false;
	
	private ImportListWrapper importListWrapper = new ImportListWrapper();
	private ServiceListWrapper serviceListWrapper = new ServiceListWrapper();
	private ResourceListWrapper resourceListWrapper = new ResourceListWrapper();

	private List<SubProcessWrapper> subProcessWrappers = new ArrayList<SubProcessWrapper>();
	
	public WorkflowProcessWrapper(ModelElement arg0) {
		super(arg0,null);
		initChildren();
		this.addPropertyChangeListener(this);
	}
	
	public ImportListWrapper getImportListWrapper(){
		return this.importListWrapper;
	}
	
	public ServiceListWrapper getServiceListWrapper(){
		return this.serviceListWrapper;
	}
	
	public ResourceListWrapper getResourceListWrapper(){
		return this.resourceListWrapper;
	}

	public List<SubProcessWrapper> getSubProcessWrappers(){
		return this.subProcessWrappers;
	}
	
	@Override
	public String getElementType() {
		return "WorkflowProcess";
	}
	
	public void addChild(Wrapper child,int index){
		if (child instanceof ServiceDefWrapper){
			child.setParent(this);
			this.serviceListWrapper.addChild(child, index);
			((WorkflowProcess)this.wfElement).addService((ServiceDef)((ServiceDefWrapper) child).getWorkflowModelElement());
			serviceListWrapper.fireStructureChange(child.getElementType(), child);
		}
		else if (child instanceof ResourceDefWrapper){
			child.setParent(this);
			this.resourceListWrapper.addChild(child,index);
			((WorkflowProcess)this.wfElement).addResource((ResourceDef)((ResourceDefWrapper)child).getWorkflowModelElement());
			resourceListWrapper.fireStructureChange(child.getElementType(), child);
		}
		
//		this.fireStructureChange(child.getElementType(), child);
	}
	
	public int deleteChild(Wrapper child){
		if (child instanceof ServiceDefWrapper){
			child.setParent(null);
			int i = this.serviceListWrapper.deleteChild(child);
			ServiceDef svc = (ServiceDef)((ServiceDefWrapper) child).getWorkflowModelElement();
			((WorkflowProcess)this.wfElement).deleteService(svc);
			return i;
		}else if (child instanceof ResourceDefWrapper){
			child.setParent(null);
			int i = this.resourceListWrapper.deleteChild(child);
			ResourceDef resource = (ResourceDef)((ResourceDefWrapper) child).getWorkflowModelElement();
			((WorkflowProcess)this.wfElement).deleteResource(resource);
			return i;
		}
		return -1;
	}

	protected void initChildren(){
		this.resourceListWrapper.setParent(this);
		this.serviceListWrapper.setParent(this);
		this.importListWrapper.setParent(this);
		
		WorkflowProcess process = (WorkflowProcess)this.getWorkflowModelElement();
		List<ServiceDef> serviceList = process.getServices();//TODO 是getServices()还是getLocalServices()呢？
		for (ServiceDef serviceDef : serviceList){
			ServiceDefWrapper wrapper = new ServiceDefWrapper(serviceDef);
			wrapper.setParent(this);
			this.serviceListWrapper.addChild(wrapper);
		}
		
		List<ResourceDef> resourceList = process.getResources();//TODO 是getResource()还是getLocalResources()呢？
		for (ResourceDef resourceDef : resourceList){
			ResourceDefWrapper wrapper = new ResourceDefWrapper(resourceDef);
			wrapper.setParent(this);
			this.resourceListWrapper.addChild(wrapper);
		}
		
		//TODO import待处理
		
		
		
		List<SubProcess> subProcesses = process.getLocalSubProcesses();
		for (SubProcess subflow : subProcesses){
			Diagram subflowDiagram = process.getDiagramBySubProcessId(subflow.getId());
			if (subflowDiagram==null){
				String diagramId = UUID.randomUUID().toString();
				subflowDiagram = new DiagramImpl(diagramId,subflow.getId());
				process.addDiagram(subflowDiagram);
			}
			
			
			//检查所有的流程元素是否有对应的Shape
			List<StartNode> startNodes = subflow.getStartNodes();
			for (StartNode startNode : startNodes) {
				StartNodeShape startNodeShape = (StartNodeShape)subflowDiagram.findChildByWorkflowElementId(startNode.getId());

				if (startNodeShape==null){

					String id = UUID.randomUUID().toString();
					startNodeShape = new StartNodeShapeImpl(id);
					startNodeShape.setWorkflowElementRef(startNode.getId());
					subflowDiagram.getWorkflowNodeShapes().add(startNodeShape);
				}
			}
			
			List<Activity> activities = subflow.getActivities();
			for (Activity activity : activities){
				ActivityShape activityShape = (ActivityShape)subflowDiagram.findChildByWorkflowElementId(activity.getId());
				if (activityShape==null){
					String id = UUID.randomUUID().toString();
					activityShape = new ActivityShapeImpl(id);
					activityShape.setWorkflowElementRef(activity.getId());
					subflowDiagram.getWorkflowNodeShapes().add(activityShape);
				}
			}
			
			List<Router> routers = subflow.getRouters();
			for (Router router : routers){
				RouterShape routerShape = (RouterShape)subflowDiagram.findChildByWorkflowElementId(router.getId());
				if (routerShape==null){
					String id = UUID.randomUUID().toString();
					routerShape = new RouterShapeImpl(id);
					routerShape.setWorkflowElementRef(router.getId());
					subflowDiagram.getWorkflowNodeShapes().add(routerShape);
				}
				
			}
			
			List<EndNode> endnodes = subflow.getEndNodes();
			for (EndNode endnode : endnodes){
				EndNodeShape endNodeShape = (EndNodeShape)subflowDiagram.findChildByWorkflowElementId(endnode.getId());
				
				if (endNodeShape==null){
					String id = UUID.randomUUID().toString();
					endNodeShape = new EndNodeShapeImpl(id);
					endNodeShape.setWorkflowElementRef(endnode.getId());
					subflowDiagram.getWorkflowNodeShapes().add(endNodeShape);
				}
			}
			
			List transitions = subflow.getTransitions();

			for (int i = 0; i < transitions.size(); i++) {
				Transition trans = (Transition) transitions.get(i);

				TransitionShape transShape = (TransitionShape) subflowDiagram
						.findChildByWorkflowElementId(trans.getId());

				// transition
				if (transShape == null) {
					String id = UUID.randomUUID().toString();
					transShape = new TransitionShapeImpl(id);
					transShape.setWorkflowElementRef(trans.getId());
					subflowDiagram.getTransitions().add(transShape);

					if (trans.getFromNode() != null) {
						DiagramElement source = subflowDiagram
								.findChildByWorkflowElementId(trans
										.getFromNode().getId());
						if (source != null
								&& source instanceof WorkflowNodeShape) {
							transShape
									.setFromWorkflowNodeShape((WorkflowNodeShape) source);
						}
					}
					if (trans.getToNode() != null) {
						DiagramElement target = subflowDiagram
								.findChildByWorkflowElementId(trans.getToNode()
										.getId());
						if (target != null
								&& target instanceof WorkflowNodeShape) {
							transShape
									.setToWorkflowNodeShape((WorkflowNodeShape) target);
						}
					}

				}
			}
			
			SubProcessWrapper wrapper = new SubProcessWrapper(subflow,subflowDiagram,this);
			
			subProcessWrappers.add(wrapper);
		}
	}
	
	public boolean isDirty() {
		return dirty;
	}
	
	public void setDirty(boolean b){
		this.dirty = b;
	}
	
	public void propertyChange(PropertyChangeEvent evt) {
		// TODO Auto-generated method stub
		if (!evt.getPropertyName().startsWith("SIMULATION_PROPERTY")){
			dirty = true;
		}
	}
}
